from loudml import errors
from loudml.misc import parse_timedelta, make_datetime, make_ts
from loudml.model import Model

import pandas as pd
import time
from fbprophet import Prophet
import matplotlib.pyplot as plt

from .model import (
    Model,
)
from voluptuous import (
    Required,
)
from . import (
    schemas,

)


class ProphetPrediction:
    """
    Time-series prediction
    """
    def __init__(self, model, timestamps, predicted):
        self.model = model
        self.timestamps = timestamps
        self.predicted = predicted

    def format_buckets(self):
        predict_buckets = []
        for field, results in self.predicted.items():
            for j in range(len(results)):
                bucket = {}
                if "Probability" in field:
                    bucket['timestamp'] = self.timestamps[j]
                    bucket['predicted'] = {field: results[j]}
                else:
                    bucket['timestamp'] = self.timestamps[results[j][0]]
                    bucket['predicted'] = {field: results[j][1]}
                predict_buckets.append(bucket)
        return predict_buckets


class ProphetModel(Model):
    TYPE = 'prophet'
    SCHEMA = Model.SCHEMA.extend({
        Required('bucket_interval'): schemas.TimeDelta(
            min=0, min_included=False,
        ),
    })

    def __init__(self, settings=None, state=None):
        print("### 创建loudml.prophet模型\n")
        if settings == None:
            return
        super().__init__(settings, state)
        settings = self.validate(settings)

        self.bucket_interval = parse_timedelta(settings.get('bucket_interval')).total_seconds()
        self.interval = parse_timedelta(settings.get('interval')).total_seconds()
        self.offset = parse_timedelta(settings.get('offset')).total_seconds()
        self.forecast = int(parse_timedelta(settings.get('forecast')).total_seconds())
        # no need to train, set loss = 0
        self._state = {
            'loss': 0,
        }

    @property
    def type(self):
        return self.TYPE

    @property
    def is_trained(self):
        return True  # 不需要训练

    def predict(
            self,
            datasource,
            from_date,
            to_date,
            threshold):

        period = self.build_date_range(from_date, to_date)

        # get data
        data = datasource.get_times_data(self, period.from_ts, period.to_ts)

        # 将数据存储方式变为:

        #dataset保存数据 timeset保存时间戳
        dataset = {}
        timeset = []

        for i, (_, val, timeval) in enumerate(data):
            timeset.append(timeval)
            for j, x in enumerate(val):
                feature = self.features[j]
                if dataset.get(feature.name) == None:
                    dataset[feature.name] = []
                dataset[feature.name].append(x)

        results = {}

        for feature_name in dataset:
            df = pd.DataFrame({'ds':timeset, 'y':dataset[feature_name]})
            try:
                for index, row in df.iterrows():
                    df.loc[index, 'ds'] = time.strftime("%Y-%m-%d %H:%M:%S", time.strptime(row['ds'], "%Y-%m-%dT%H:%M:%SZ"))
            except:
                print("\n### 时间格式非[%Y-%m-%dT%H:%M:%SZ]形式\n")
            m = Prophet()
            m.fit(df)
            future = m.make_future_dataframe(periods=self.forecast)
            results[feature_name] = m.predict(future)

        '''
        print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']])
        m.plot(forecast)

        x1 = forecast['ds']
        y1 = forecast['yhat']

        plt.plot(x1, y1)
        plt.show()
        '''
        return ProphetPrediction(self, timeset, results)

